package main;


import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.math.BigDecimal;
import java.util.concurrent.*;

/**
 *  @author Xu,
 *  @data 2020/11/26，
 *  @time 12:26
 *  3分钟62万位左右
 *  公式 ：pi= + 176 * arctan(1/57) + 28 * arctan(1/239) - 48 * arctan(1/682) + 96 * arctan(1/12943) [Stormer]
 *
 */
public class Pi_calculation {
    private static BigDecimal pi;
    private static int n = 620000;
    private static BigDecimal part1,part2,part3,part4;
    public static void main(String[] args) {

        Long start = System.currentTimeMillis();

        ExecutorService executorService = new ThreadPoolExecutor(4, 4, 0L,
                TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(10),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

        executorService.execute(new Runnable() {
            @Override
            public void run() {
                part1 = arcTan(57).multiply(new BigDecimal(176));
            }
        });
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                part2 = arcTan(239).multiply(new BigDecimal(28));
            }
        });
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                part3 = arcTan(682).multiply(new BigDecimal(-48));
            }
        });
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                part4 = arcTan(12943).multiply(new BigDecimal(96));
            }
        });
        executorService.shutdown();
        while(!executorService.isTerminated()){ }
        pi = part1.add(part2).add(part3).add(part4);
        System.out.println(pi.toString());
        System.out.println("小数位： " + (pi.toString().length()-2));
        Long end = System.currentTimeMillis();
        System.out.println("计算"+n+"位耗时："+(end-start)/1000.0+"秒");

        createTable();
    }

    /**
     * arctan运算
     * @param x
     * @return
     */
    public static BigDecimal arcTan(int x){
        //为了防误差
        int n2 = n+2;
        BigDecimal result = BigDecimal.ZERO;
        BigDecimal xsquare = new BigDecimal(x*x);
        BigDecimal bigx = new BigDecimal(x);
        BigDecimal temp;
        BigDecimal res = BigDecimal.ONE.divide(bigx , n2, BigDecimal.ROUND_HALF_EVEN);

        boolean b = true;
        for(int i=1;;i+=2){
            temp = res.divide(new BigDecimal(i), n2, BigDecimal.ROUND_HALF_EVEN);
            if(temp.compareTo(BigDecimal.ZERO)==0){
                break;
            }
            if(b){
                result = result.add(temp);
            }else{
                result = result.subtract(temp);
            }
            b = !b;
            res = res.divide(xsquare, n2, BigDecimal.ROUND_HALF_EVEN);
        }
        return result;
    }

    public static void createTable() {
        String path = "./src/output.txt";
        BufferedOutputStream bufferedOutputStream = null;
        FileOutputStream outputStream = null;
        StringBuffer stringBuffer;
        try {
            outputStream = new FileOutputStream(new File(path));
            bufferedOutputStream = new BufferedOutputStream(outputStream);
            stringBuffer = new StringBuffer();
            stringBuffer.append(pi.toString());
            bufferedOutputStream.write(stringBuffer.toString().getBytes("UTF-8"));
            bufferedOutputStream.flush();
            bufferedOutputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                bufferedOutputStream.close();
                outputStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

